package net.goutalk.glcs.module.organization.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.base.MPJBaseServiceImpl;
import net.goutalk.glcs.common.constant.GlobalConstant;
import net.goutalk.glcs.common.exception.MyException;
import net.goutalk.glcs.common.page.ConventPage;
import net.goutalk.glcs.common.page.PageOutput;
import net.goutalk.glcs.common.utils.RedisUtil;
import net.goutalk.glcs.common.utils.VoToColumnUtil;
import net.goutalk.glcs.module.organization.dto.AddUserDto;
import net.goutalk.glcs.module.organization.dto.UpdateUserDto;
import net.goutalk.glcs.module.organization.dto.WeChatPageDto;
import net.goutalk.glcs.module.organization.entity.User;
import net.goutalk.glcs.module.organization.entity.UserDeptRelation;
import net.goutalk.glcs.module.organization.entity.UserPostRelation;
import net.goutalk.glcs.module.organization.entity.UserRoleRelation;
import net.goutalk.glcs.module.organization.mapper.UserDeptRelationMapper;
import net.goutalk.glcs.module.organization.mapper.UserMapper;
import net.goutalk.glcs.module.organization.mapper.UserPostRelationMapper;
import net.goutalk.glcs.module.organization.mapper.UserRoleRelationMapper;
import net.goutalk.glcs.module.organization.service.IUserDeptRelationService;
import net.goutalk.glcs.module.organization.service.IUserService;
import net.goutalk.glcs.module.organization.vo.UserInfoVo;
import net.goutalk.glcs.module.organization.vo.WeChatPageVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author tanyujie
 * @since 2022-03-02
 */
@Service
@AllArgsConstructor
public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, User> implements IUserService {

    private final UserMapper userMapper;

    private final UserDeptRelationMapper userDeptRelationMapper;

    private final IUserDeptRelationService userDeptRelationService;

    private final UserRoleRelationMapper userRoleRelationMapper;

    private final UserPostRelationMapper userPostRelationMapper;

    private final RedisUtil redisUtil;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(AddUserDto dto) {
        long count = count(Wrappers.<User>query().lambda().eq(User::getUserName, dto.getUserName()).or().eq(User::getCode, dto.getCode()));
        if (count > 0) {
            throw new MyException("用户名称或编码已存在");
        }
        User user = BeanUtil.toBean(dto, User.class);

        //密码加密加盐存储到数据库
        user.setPassword(SaSecureUtil.md5BySalt(dto.getPassword(), GlobalConstant.SECRET_KEY));
        save(user);

        List<UserDeptRelation> userDeptRelationList = new ArrayList<>();
        if (StrUtil.isNotBlank(dto.getDepartmentIds())){
            String allDeptIdStr = StrUtil.join(StringPool.COMMA, dto.getDepartmentIds());
            List<Long> departmentIds = Arrays.stream(allDeptIdStr.split(StringPool.COMMA)).map(Convert::toLong).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(departmentIds)){
                for (Long deptId : departmentIds) {
                    //将用户所选部门保存到关联表中
                    UserDeptRelation userDeptRelation = new UserDeptRelation();
                    userDeptRelation.setUserId(user.getId());
                    userDeptRelation.setDeptId(deptId);
                    userDeptRelationList.add(userDeptRelation);
                }
            }
          userDeptRelationService.saveBatch(userDeptRelationList);
        }

        CompletableFuture.runAsync(() -> {
            List<User> list = list();
            redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);

            List<UserDeptRelation> deptRelationList = userDeptRelationMapper.selectList(Wrappers.lambdaQuery(UserDeptRelation.class));
            redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, deptRelationList);
        });

        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(UpdateUserDto dto) {
        long count = count(Wrappers.<User>query().lambda()
                .eq(User::getCode, dto.getCode())
                .ne(User::getId, dto.getId()));

        if (count > 0) {
            throw new MyException("用户名称或编码已存在");
        }

        User user = BeanUtil.toBean(dto, User.class);

        updateById(user);

        //先删除再新增
        userDeptRelationService.remove(Wrappers.<UserDeptRelation>query().lambda().eq(UserDeptRelation::getUserId,user.getId()));
        List<UserDeptRelation> userDeptRelationList = new ArrayList<>();
        if (StrUtil.isNotBlank(dto.getDepartmentIds())){
            String allDeptIdStr = StrUtil.join(StringPool.COMMA, dto.getDepartmentIds());
            List<Long> departmentIds = Arrays.stream(allDeptIdStr.split(StringPool.COMMA)).map(Convert::toLong).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(departmentIds)){
                for (Long deptId : departmentIds) {
                    //将用户所选部门保存到关联表中
                    UserDeptRelation userDeptRelation = new UserDeptRelation();
                    userDeptRelation.setUserId(user.getId());
                    userDeptRelation.setDeptId(deptId);
                    userDeptRelationList.add(userDeptRelation);
                }
            }
            userDeptRelationService.saveBatch(userDeptRelationList);
        }


        CompletableFuture.runAsync(() -> {
            List<User> list = list();
            redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);

            List<UserDeptRelation> deptRelationList = userDeptRelationMapper.selectList(Wrappers.lambdaQuery(UserDeptRelation.class));
            redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, deptRelationList);
        });
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteBatch(List<Long> ids) {
        //删除时需要同时删除用户部门关联表和用户角色关联表和用户岗位关系表数据。
        this.removeBatchByIds(ids);
        //根据用户ids去缓存中查询到对应的三个表的数据
        List<UserDeptRelation> userDeptRelationList = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
        });
        List<UserPostRelation> userPostRelationList = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
        });
        List<UserRoleRelation> userRoleRelationList = redisUtil.get(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, new TypeReference<List<UserRoleRelation>>() {
        });
        //拿用户ids进行过滤，如果存在，就删除
        List<Long> deptRelationIds = userDeptRelationList.stream().filter(u -> ids.contains(u.getUserId())).map(UserDeptRelation::getId).collect(Collectors.toList());
        List<Long> postRelationIds = userPostRelationList.stream().filter(u -> ids.contains(u.getUserId())).map(UserPostRelation::getId).collect(Collectors.toList());
        List<Long> roleRelationIds = userRoleRelationList.stream().filter(u -> ids.contains(u.getUserId())).map(UserRoleRelation::getId).collect(Collectors.toList());
        //调用三个表的删除
        if(CollectionUtil.isNotEmpty(deptRelationIds)){
            userDeptRelationMapper.deleteBatchIds(deptRelationIds);
        }
        if(CollectionUtil.isNotEmpty(postRelationIds)) {
            userPostRelationMapper.deleteBatchIds(postRelationIds);
        }
        if(CollectionUtil.isNotEmpty(roleRelationIds)) {
            userRoleRelationMapper.deleteBatchIds(roleRelationIds);
        }
        //更新缓存
        CompletableFuture.runAsync(() -> {
            List<User> list = this.list();
            redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);

            List<UserDeptRelation> deptRelationList = userDeptRelationMapper.selectList(Wrappers.lambdaQuery(UserDeptRelation.class));
            redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, deptRelationList);

            List<UserPostRelation> postRelationList = userPostRelationMapper.selectList(Wrappers.lambdaQuery(UserPostRelation.class));
            redisUtil.set(GlobalConstant.USER_POST_RELATION_CACHE_KEY, postRelationList);

            List<UserRoleRelation> roleRelationList = userRoleRelationMapper.selectList(Wrappers.lambdaQuery(UserRoleRelation.class));
            redisUtil.set(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, roleRelationList);
        });
        return Boolean.TRUE;
    }

    @Override
    public List<UserInfoVo> getUsersInfo(String ids) {

        List<String> idList = Arrays.stream(ids.split(",")).collect(Collectors.toList());
        if (idList.size() == 0) {
            return new ArrayList<>();
        }

        List<User> list = userMapper.selectList(Wrappers.lambdaQuery(User.class)
                .in(User::getId, idList)
                .select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserInfoVo.class).contains(x.getProperty())));

        return BeanUtil.copyToList(list, UserInfoVo.class);
    }

    @Override
    public PageOutput<WeChatPageVO> getPage(WeChatPageDto dto) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.like(StrUtil.isNotBlank(dto.getKeyword()),User::getName,dto.getKeyword())
                 .select(User.class,x -> VoToColumnUtil.fieldsToColumns(WeChatPageVO.class).contains(x.getProperty()));
        IPage<User> page = userMapper.selectPage(ConventPage.getPage(dto), queryWrapper);
        List<User> records = page.getRecords();
        for (User record : records) {
            record.setRemark("员工更新成功");
            record.setSortCode(1);
        }
        return ConventPage.getPageOutput(page, WeChatPageVO.class);

    }
}
